package xworker.netty.handlers.message;

import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.xmeta.ActionContext;
import org.xmeta.Thing;
import org.xmeta.cache.ThingEntry;
import xworker.netty.NettySession;
import xworker.lang.executor.Executor;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@ChannelHandler.Sharable
public class HandlerManager extends SimpleChannelInboundHandler<Object> {
    private static final String TAG = HandlerManager.class.getName();

    final Map<String, MessageHandler> handlerMap = new HashMap<>();
    final Map<String, HandlerExecutor> methodMap = new HashMap<>();
    final Map<String, Thing> actionMap = new HashMap<>();
    final List<MessageHandlers> messageHandlers = new ArrayList<>();

    Thing thing;
    ActionContext actionContext;
    ThingEntry thingEntry;
    long lastCheckTime = System.currentTimeMillis();

    public HandlerManager(Thing thing, ActionContext parentContext){
        this.thing = thing;
        this.actionContext = new ActionContext();
        this.actionContext.put("parentContext", parentContext);
        thingEntry = new ThingEntry(thing);

        init();
    }

    private void init(){
        //初始化变量
        for(Thing variables : thing.getChilds("Variables")){
            variables.doAction("create", actionContext);
        }

        Class<?>[] classes = thing.doAction("getClasses", actionContext);

        if(classes != null){
            for(Class<?> cls : classes){
                regist(cls);
            }
        }

        messageHandlers.clear();
        List<Thing> messageHandlers = thing.doAction("getMessageHandlers", actionContext);
        for(Thing child : messageHandlers){
            child.doAction("initHandlers", actionContext, "handlerManager", this);
        }
    }

    public void regist(String className, MessageHandler messageHandler){
        handlerMap.put(className, messageHandler);
    }

    public void addMessageHandlers(MessageHandlers messageHandler){
        messageHandlers.add(messageHandler);
    }

    public void regist(String className, Thing action){
        actionMap.put(className, action);
    }

    public void regist(Method method){
        Handler annotation = method.getAnnotation(Handler.class);
        //System.out.println(method.getName() + ":" + annotation);
        if(annotation != null) {
            if(annotation.request() != null && !annotation.request().isEmpty()){
                methodMap.put(annotation.request(),  new HandlerExecutor(annotation, method));
            }

            if(annotation.requestClass() != null){
                methodMap.put(annotation.requestClass().getName(), new HandlerExecutor(annotation, method));
            }
        }else{
            Executor.warn(TAG, "Can not regist " + method + ", no Handler annotation.");
        }
    }

    public void regist(Class<?> cls){
        for(Method method : cls.getMethods()) {
            Handler annotation = method.getAnnotation(Handler.class);
            //System.out.println(method.getName() + ":" + annotation);
            if(annotation != null) {
                if(annotation.request() != null && !annotation.request().isEmpty()){
                    methodMap.put(annotation.request(),  new HandlerExecutor(annotation, method));
                }

                if(annotation.requestClass() != null){
                    methodMap.put(annotation.requestClass().getName(), new HandlerExecutor(annotation, method));
                }
            }
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        if(msg != null) {
            synchronized (this) {
                //检测配置模型是否已经更新，为避免检测过于频繁，每2秒一次
                if(System.currentTimeMillis() - lastCheckTime > 2000) {
                    lastCheckTime = System.currentTimeMillis();
                    if (thingEntry.isChanged()) {
                        this.thing = thingEntry.getThing();
                        init();
                    }

                    for(MessageHandlers handlers : messageHandlers){
                        handlers.checkInit();
                    }
                }
            }

            String name = msg.getClass().getName();
            MessageHandler messageHandler = handlerMap.get(name);
            if(messageHandler != null){
                messageHandler.channelRead(ctx, msg);
            }else {
                HandlerExecutor method = methodMap.get(name);
                if (method != null) {
                    method.execute(ctx, msg);
                } else {
                    Thing action = actionMap.get(name);
                    if (action != null) {
                        action.doAction("handleMessage", actionContext, "msg", msg, "session", NettySession.getSession(ctx), "ctx", ctx);
                    } else {
                        //没有可以处理的，传递到后续Handler
                        ctx.fireChannelRead(msg);
                    }
                }
            }
        }
    }

    public static HandlerManager create(ActionContext actionContext){
        Thing self = actionContext.getObject("self");

        return new HandlerManager(self, actionContext);
    }

    public static void createVariables(ActionContext actionContext){
        Thing self = actionContext.getObject("self");

        for(Thing thing : self.getChilds()){
            Object result = thing.getAction().run(actionContext);
            actionContext.g().put(thing.getMetadata().getName(), result);
        }
    }
}
